package ar.edu.untref.robotica.simulador;

import java.awt.Color;
import java.awt.Image;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class Escenario {

	private Image imagen;
	private int[][] matriz;
	private Posicion posicionRobot;
	private Set<Rectangle2D> obstaculos;

	// una celda es...centímetros
	private double relacionCentimetroCelda;

	public Escenario(Image imagen) {

		this.imagen = imagen;
		this.posicionRobot = Configuracion.instancia().getPosicionInicial();
		this.relacionCentimetroCelda = Configuracion.instancia()
				.getRelacionCentimetroCelda();

		this.matriz = imagenAMatriz((BufferedImage) imagen);
	}

	private int[][] imagenAMatriz(BufferedImage imagen) {

		int w = imagen.getWidth();
		int h = imagen.getHeight();

		int[][] array = new int[w][h];
		for (int j = 0; j < w; j++) {
			for (int k = 0; k < h; k++) {
				Color c = new Color(imagen.getRGB(j, k));
				int red = c.getRed();
				int green = c.getGreen();
				int blue = c.getBlue();
				if (red == 0 && green == 0 && blue == 0) {
					array[j][k] = 1;
				}
			}
		}

		return array;
	}

	public int[][] getMatriz() {
		return this.matriz;
	}

	public Posicion getPosicionRobot() {
		return this.posicionRobot;
	}

	public void aumentarX() {
		this.posicionRobot.setPosicionX(this.posicionRobot.getPosicionX() + 1);
	}

	public void disminuirX() {
		this.posicionRobot.setPosicionX(this.posicionRobot.getPosicionX() - 1);
	}

	public void aumentarY() {
		this.posicionRobot.setPosicionY(this.posicionRobot.getPosicionY() + 1);
	}

	public void disminuirY() {
		this.posicionRobot.setPosicionY(this.posicionRobot.getPosicionY() - 1);
	}

	public void aumentarAngulo(double cantidad) {
		double nuevoAngulo = this.posicionRobot.getAngulo() + cantidad;
		this.posicionRobot.setAngulo(nuevoAngulo);
	}

	public void disminuirAngulo(double cantidad) {
		double nuevoAngulo = this.posicionRobot.getAngulo() - cantidad;
		this.posicionRobot.setAngulo(nuevoAngulo);
	}

	public Image getImagen() {
		return imagen;
	}

	private Point2D.Double getCentroRobot() {

		Posicion posicionRobot = this.getPosicionRobot();

		Point2D.Double centroRobot = new Point2D.Double(
				posicionRobot.getPosicionX(), posicionRobot.getPosicionY());

		return centroRobot;
	}

	public Shape getShapeRobot() {

		double altoRobot = Configuracion.instancia().getAltoRobot();
		double anchoRobot = Configuracion.instancia().getAnchoRobot();

		Posicion posicionRobot = this.getPosicionRobot();

		Path2D path = new Path2D.Double();

		List<Point2D.Double> puntos = new LinkedList<Point2D.Double>();

		Point2D.Double punto0 = new Point2D.Double(posicionRobot.getPosicionX()
				- (anchoRobot / relacionCentimetroCelda) / 2,
				posicionRobot.getPosicionY()
						- (altoRobot / relacionCentimetroCelda) / 2);

		Point2D.Double punto1 = new Point2D.Double(punto0.getX() + anchoRobot
				/ relacionCentimetroCelda, punto0.getY());

		Point2D.Double punto2 = new Point2D.Double(punto1.getX(), punto1.getY()
				+ altoRobot / relacionCentimetroCelda);

		Point2D.Double punto3 = new Point2D.Double(punto0.getX(), punto2.getY());

		puntos.add(punto0);
		puntos.add(punto1);
		puntos.add(punto2);
		puntos.add(punto3);

		// Rotar
		for (int i = 0; i < puntos.size(); i++) {
			this.rotar(puntos.get(i), getCentroRobot(), this.getPosicionRobot()
					.getAngulo());
		}

		// Recorrer path
		path.moveTo(punto0.getX(), punto0.getY());
		for (int i = 1; i < puntos.size(); i++) {
			path.lineTo(puntos.get(i).getX(), puntos.get(i).getY());
		}
		path.closePath();

		return path.createTransformedShape(null);
	}

	public Shape getIndicacionRobot() {

		double altoRobot = Configuracion.instancia().getAltoRobot();
		double anchoRobot = Configuracion.instancia().getAnchoRobot();

		Posicion posicionRobot = this.getPosicionRobot();

		Path2D path = new Path2D.Double();

		List<Point2D.Double> puntos = new LinkedList<Point2D.Double>();

		Point2D.Double punto0 = new Point2D.Double(posicionRobot.getPosicionX()
				- (anchoRobot / relacionCentimetroCelda) / 2,
				posicionRobot.getPosicionY()
						- (altoRobot / relacionCentimetroCelda) / 2);

		Point2D.Double punto1 = new Point2D.Double(punto0.getX() + anchoRobot
				/ relacionCentimetroCelda, punto0.getY());

		Point2D.Double punto2 = new Point2D.Double(punto1.getX(), punto1.getY()
				+ altoRobot / relacionCentimetroCelda);

		Point2D.Double punto3 = new Point2D.Double(punto0.getX(), punto2.getY());

		Point2D.Double puntoSuperior = new Point2D.Double(
				posicionRobot.getPosicionX(), punto0.getY());

		puntos.add(puntoSuperior);
		puntos.add(punto2);
		puntos.add(punto3);

		// Rotar
		for (int i = 0; i < puntos.size(); i++) {
			this.rotar(puntos.get(i), getCentroRobot(), this.getPosicionRobot()
					.getAngulo());
		}

		// Recorrer path
		path.moveTo(puntoSuperior.getX(), puntoSuperior.getY());
		for (int i = 1; i < puntos.size(); i++) {
			path.lineTo(puntos.get(i).getX(), puntos.get(i).getY());
		}
		path.closePath();

		return path.createTransformedShape(null);
	}

	private void rotar(Point2D.Double point, Point2D.Double center, double angle) {

		AffineTransform rotation = new AffineTransform();
		rotation.rotate(Math.toRadians(angle), center.getX(), center.getY());
		rotation.transform(point, point);
	}

	public Set<Rectangle2D> getShapesObstaculos() {

		Set<Rectangle2D> obstaculos = new HashSet<Rectangle2D>();
		int[][] matriz = this.getMatriz();

		for (int i = 0; i < matriz.length; i++) {

			for (int j = 0; j < matriz[0].length; j++) {

				if ((int) matriz[i][j] == 1) {

					Rectangle2D.Double figura = new Rectangle2D.Double(i, j,
							relacionCentimetroCelda, relacionCentimetroCelda);
					obstaculos.add(figura);
				}
			}
		}

		return obstaculos;
	}

	public boolean choque() { // LENTO!

		Iterator<Rectangle2D> it = this.obstaculos.iterator();

		while (it.hasNext()) {

			if (getShapeRobot().intersects(it.next())) {

				return true;
			}
		}

		return false;
	}

}